#include "PracticeMode.h"
#include "../Game.h"
#include "../SGD Wrappers\SGD_InputManager.h"
#include "GameState.h"
#include "MainMenuState.h"
#include "GameMode.h"
#include "../tile/TileManager.h"

#include "../source/Player.h"
#include "../source/Gorbi.h"
#include "../source/Wall.h"
#include "../source/Ball.h"
#include "../source/Ally.h"
#include "../source/PowerUp.h"
#include "../source/Cannyble.h"
#include "../Punch.h"
#include "../source/Runner.h"
#include "../source/Bomber.h"
#include "../source/Striker.h"
#include "../source/Tank.h"

#include "../SGD Wrappers/EntityManager.h"
#include "../SGD Wrappers/SGD_GraphicsManager.h"
#include "GameState.h"

#define BUCKET_PLAYERS 0
#define BUCKET_ENEMIES 1
#define BUCKET_GORBI 2
#define BUCKET_BALL 3
#define BUCKET_WALLS 4
#define BUCKET_POWERUPS 5
#define BUCKET_PUNCH 6
#define BUCKET_SPEAR 7
#define BUCKET_GOALIE 8

CPracticeMode* CPracticeMode::GetInstance(void)
{
	static CPracticeMode s_Instance;
	return &s_Instance;
}

void CPracticeMode::Enter(void)
{
	CAnimationManager::GetInstance()->Initialize();

	CTileManager::GetInstance()->LoadLevel("Level3.xml");

	m_pEntities = new EntityManager;

	Game::GetInstance()->SetMiniGame(false);

	m_TopWall = new CWall;
	m_TopWall->SetPosition({ 0, -100 });
	m_TopWall->SetSize({ Game::GetInstance()->GetScreenWidth(), 100 });
	m_TopWall->SetColor({ 255, 0, 0, 0 });
	m_TopWall->SetImpentrable(true);
	m_pEntities->AddEntity(m_TopWall, BUCKET_WALLS);

	m_BotWall = new CWall;
	m_BotWall->SetPosition({ 0, Game::GetInstance()->GetScreenHeight() - 1 });
	m_BotWall->SetSize({ Game::GetInstance()->GetScreenWidth(), 100 });
	m_BotWall->SetColor({ 255, 0, 0, 0 });
	m_BotWall->SetImpentrable(true);
	m_pEntities->AddEntity(m_BotWall, BUCKET_WALLS);


	m_LeftWall = new CWall;
	m_LeftWall->SetPosition({ -100, 0 });
	m_LeftWall->SetSize({ 100, Game::GetInstance()->GetScreenHeight() });
	m_LeftWall->SetColor({ 0, 0, 0, 0 });
	m_LeftWall->SetImpentrable(true);
	m_pEntities->AddEntity(m_LeftWall, BUCKET_WALLS);

	m_RightWall = new CWall;
	m_RightWall->SetPosition({ Game::GetInstance()->GetScreenWidth(), 0 });
	m_RightWall->SetSize({ 100, Game::GetInstance()->GetScreenHeight() });
	m_RightWall->SetColor({ 0, 0, 0, 0 });
	m_RightWall->SetImpentrable(true);
	m_pEntities->AddEntity(m_RightWall, BUCKET_WALLS);


	testBall = dynamic_cast<CBall*>(CreateBall(CTileManager::GetInstance()->SpawnEntity(m_nEntitySpawnIndex), { 32, 32 }));
	m_nEntitySpawnIndex++;
	testBall->SetColor({ 255, 0, 255 });
	m_AllEnts.push_back(testBall);
	m_pEntities->AddEntity(testBall, BUCKET_BALL);

	m_pPlayer1 = new CRunner;
	m_pPlayer1->SetPosition(CTileManager::GetInstance()->SpawnEntity(m_nEntitySpawnIndex));
	m_pPlayer1->SetSize({ 32, 64 });
	m_pPlayer1->SetControllernumber(0);
	m_nEntitySpawnIndex++;
	m_pPlayer1->SetBall(testBall);
	m_AllEnts.push_back(m_pPlayer1);
	m_pEntities->AddEntity(m_pPlayer1, BUCKET_PLAYERS);

	CAnimationManager::GetInstance()->SetOwner(m_pPlayer1, "runnerIdleR");
	CAnimationManager::GetInstance()->AddAnim(&m_pPlayer1->currAnimation);
	
	m_pCurrPlayer = m_pPlayer1;

	m_pPlayer2 = new CStriker;
	m_pPlayer2->SetPosition(CTileManager::GetInstance()->SpawnEntity(m_nEntitySpawnIndex));
	m_pPlayer2->SetSize({ 32, 64 });
	m_pPlayer2->SetControllernumber(1);
	m_nEntitySpawnIndex++;
	m_pPlayer2->SetBall(testBall);
	m_AllEnts.push_back(m_pPlayer2);
	m_pEntities->AddEntity(m_pPlayer2, BUCKET_PLAYERS);

	CAnimationManager::GetInstance()->SetOwner(m_pPlayer2, "strikerIdleB");
	CAnimationManager::GetInstance()->AddAnim(&m_pPlayer2->currAnimation);

	m_pPlayer3 = new CTank;
	m_pPlayer3->SetPosition(CTileManager::GetInstance()->SpawnEntity(m_nEntitySpawnIndex));
	m_pPlayer3->SetSize({ 32, 64 });
	m_pPlayer3->SetControllernumber(1);
	m_nEntitySpawnIndex++;
	m_pPlayer3->SetBall(testBall);
	m_AllEnts.push_back(m_pPlayer3);
	m_pEntities->AddEntity(m_pPlayer3, BUCKET_PLAYERS);

	CAnimationManager::GetInstance()->SetOwner(m_pPlayer3, "tankIdleB");
	CAnimationManager::GetInstance()->AddAnim(&m_pPlayer3->currAnimation);

	m_pPlayer4 = new CBomber;
	m_pPlayer4->SetPosition(CTileManager::GetInstance()->SpawnEntity(m_nEntitySpawnIndex));
	m_pPlayer4->SetSize({ 32, 64 });
	m_pPlayer4->SetControllernumber(1);
	m_nEntitySpawnIndex++;
	m_pPlayer4->SetBall(testBall);
	m_AllEnts.push_back(m_pPlayer4);
	m_pEntities->AddEntity(m_pPlayer4, BUCKET_PLAYERS);

	CAnimationManager::GetInstance()->SetOwner(m_pPlayer4, "bomberIdleB");
	CAnimationManager::GetInstance()->AddAnim(&m_pPlayer4->currAnimation);


	testGorbi = new CGorbi;
	testGorbi->SetPosition(CTileManager::GetInstance()->SpawnEntity(m_nEntitySpawnIndex));
	testGorbi->SetSize({ 32, 32 });
	testGorbi->SetColor({ 0, 255, 255 });
	testGorbi->SetHomePos(testGorbi->GetPosition());
	testGorbi->SetBall(testBall);
	testGorbi->SetBallHome(testBall->GetPosition());
	m_AllEnts.push_back(testGorbi);
	m_pEntities->AddEntity(testGorbi, BUCKET_GORBI);

	m_nEntitySpawnIndex++;

	for (int numTallWalls = 0; numTallWalls < CTileManager::GetInstance()->GetCount(0); numTallWalls++)
	{
		testWall = dynamic_cast<CWall*>(CreateWall(CTileManager::GetInstance()->SpawnEntity(m_nEntitySpawnIndex), { 32, 32 }, true));
		testWall->SetColor({ 150, 255, 150 });
		m_AllEnts.push_back(testWall);
		m_pEntities->AddEntity(testWall, BUCKET_WALLS);
		testWall->Release();
		m_nEntitySpawnIndex++;
	}

	for (int numShortWalls = 0; numShortWalls < CTileManager::GetInstance()->GetCount(1); numShortWalls++)
	{
		testWall = dynamic_cast<CWall*>(CreateWall(CTileManager::GetInstance()->SpawnEntity(m_nEntitySpawnIndex), { 32, 32 }, false));
		testWall->SetColor({ 100, 255, 100 });
		m_AllEnts.push_back(testWall);
		m_pEntities->AddEntity(testWall, BUCKET_WALLS);
		testWall->Release();
		m_nEntitySpawnIndex++;
	}

	int numPatrollers = 0;
	for (int numEnemies = 0; numEnemies < CTileManager::GetInstance()->GetCount(2); numEnemies++)
	{
		testCannyble = dynamic_cast<CCannyble*>(CreateCannyble(CTileManager::GetInstance()->SpawnEntity(m_nEntitySpawnIndex), { 32, 32 }));
		testCannyble->SetColor({ 255, 255, 100 });

		if (CTileManager::GetInstance()->GetNumWaypoints(numEnemies) > 0)
		{
			testCannyble->AddWaypoints(testCannyble->GetHomePos());
			for (int numWaypoints = 0; numWaypoints < CTileManager::GetInstance()->GetNumWaypoints(numEnemies); numWaypoints++)
			{
				testCannyble->AddWaypoints(CTileManager::GetInstance()->GetWaypoints(numPatrollers));
			}
			testCannyble->SwitchStates(CAI::PATROL_STATE);
			numPatrollers++;
		}

		m_Cannys.push_back(testCannyble);
		m_AllEnts.push_back(testCannyble);
		m_pEntities->AddEntity(testCannyble, BUCKET_ENEMIES);
		testCannyble->Release();
		m_nEntitySpawnIndex++;
	}
}

void CPracticeMode::Exit(void)
{
	m_nEntitySpawnIndex = 0;

	if (m_pPlayer1 != nullptr)
	{
		m_pPlayer1->Release();
		m_pPlayer1 = nullptr;
	}

	if (m_pPlayer2 != nullptr)
	{
		m_pPlayer2->Release();
		m_pPlayer2 = nullptr;
	}

	if (m_pPlayer3 != nullptr)
	{
		m_pPlayer3->Release();
		m_pPlayer3 = nullptr;
	}

	if (m_pPlayer4 != nullptr)
	{
		m_pPlayer4->Release();
		m_pPlayer4 = nullptr;
	}

	if (testBall != nullptr)
	{
		testBall->Release();
		testBall = nullptr;
	}

	if (testGorbi != nullptr)
	{
		testGorbi->Release();
		testGorbi = nullptr;
	}

	if (m_BotWall != nullptr)
	{
		m_BotWall->Release();
		m_BotWall = nullptr;
	}

	if (m_LeftWall != nullptr)
	{
		m_LeftWall->Release();
		m_LeftWall = nullptr;
	}

	if (m_TopWall != nullptr)
	{
		m_TopWall->Release();
		m_TopWall = nullptr;
	}

	if (m_RightWall != nullptr)
	{
		m_RightWall->Release();
		m_RightWall = nullptr;
	}

	m_AllEnts.clear();

	if (m_pEntities != nullptr)
	{
		m_pEntities->RemoveAll();
		delete m_pEntities;
		m_pEntities = nullptr;
	}

	CTileManager::GetInstance()->UnloadLevel();
	CTileManager::DeleteInstance();

	CAnimationManager::GetInstance()->RemoveAll();
	CAnimationManager::GetInstance()->DeleteInstance();
}

bool CPracticeMode::Input(void)
{
	SGD::InputManager* pInput = SGD::InputManager::GetInstance();

	if (pInput->IsKeyPressed(SGD::Key::Escape) == true || pInput->IsButtonPressed(0, 1) == true)
	{
		Game::GetInstance()->ChangeState(CGameMode::GetInstance());
		return true;
	}
	return true;
}

void CPracticeMode::Update(float elapsedTime)
{
	HandleCollision();
	m_fPunchTimer -= elapsedTime;

	m_pCurrPlayer->SetAbilityDelay(0);
	m_pCurrPlayer->SetCharge(60);
	m_pEntities->UpdateAll(elapsedTime);
	CAnimationManager::GetInstance()->UpdateAll(elapsedTime);
}

void CPracticeMode::Render(void)
{
	CTileManager::GetInstance()->Render();
	

	SGD::GraphicsManager* pGraphics = SGD::GraphicsManager::GetInstance();
	const Font* pFont = Game::GetInstance()->GetFont();

	m_pEntities->RenderAll();

	pGraphics->DrawRectangle({ 0, 500, Game::GetInstance()->GetScreenWidth(), 600 }, { 127, 0, 0, 0 }, { 0, 0, 0 }, 6);

	if (m_bHighWalls == true)
	{
		pFont->Draw("High Walls: act as obstacles, \n cant throw over them", { 6, 506 }, 0.5f, { 255, 255, 255 });
	}
	else if (m_bLowWalls == true)
	{
		pFont->Draw("Low Walls: act as obstacles, \n can throw over them", { 6, 506 }, 0.5f, { 255, 255, 255 });
	}
	else if (m_bBalls == true)
	{
		pFont->Draw("Ball: Pick up and move to the \n oposite teams base to score", { 6, 506 }, 0.5f, { 255, 255, 255 });
	}
	else if (m_bRunner == true)
	{
		pFont->Draw("Runner: Fast moving class but \n weak in combat", { 6, 506 }, 0.5f, { 255, 255, 255 });
	}
	else if (m_bTank == true)
	{
		pFont->Draw("Tank: Defensive, slow class", { 6, 506 }, 0.5f, { 255, 255, 255 });
	}
	else if (m_bStriker == true)
	{
		pFont->Draw("Striker: Class that focuses on \n melee combat and stealing the ball", { 6, 506 }, 0.5f, { 255, 255, 255 });
	}
	else if (m_bBomber == true)
	{
		pFont->Draw("Bomber: Class that focuses on \n ranged combat and throwing the ball", { 6, 506 }, 0.5f, { 255, 255, 255 });
	}
	else if (m_bGorbi == true)
	{
		pFont->Draw("Gorbi: Guard the ball from thieves", { 6, 506 }, 0.5f, { 255, 255, 255 });
	}
	else if (m_bCannybles == true)
	{
		pFont->Draw("Cannybles: Attack players around them", { 6, 506 }, 0.5f, { 255, 255, 255 });
	}
	else if (m_bPowerups == true)
	{
		pFont->Draw("Powerups: Buffs the player or \n team that picks them up", { 6, 506 }, 0.5f, { 255, 255, 255 });
	}
	else
	{
		pFont->Draw("Practice Mode", { 6, 506 }, 1, { 255, 255, 255 });
	}

	CAnimationManager::GetInstance()->RenderAll();

}

Entity* CPracticeMode::CreateBall(SGD::Point position, SGD::Size size)
{
	CBall* tempBall = new CBall;

	tempBall->SetPosition(position);
	tempBall->SetSize(size);
	tempBall->SetVelocity({ 0, 0 });

	return tempBall;
}

Entity* CPracticeMode::CreateWall(SGD::Point position, SGD::Size size, bool highLow)
{
	CWall* tempWall = new CWall;

	tempWall->SetHeight(highLow);
	tempWall->SetPosition(position);
	tempWall->SetSize(size);
	tempWall->SetVelocity({ 0, 0 });
	tempWall->ToggleActive(true);

	return tempWall;
}

Entity* CPracticeMode::CreateCannyble(SGD::Point position, SGD::Size size)
{
	CCannyble* tempCannyble = new CCannyble;

	tempCannyble->SetPosition(position);
	tempCannyble->SetHomePos(position);
	tempCannyble->SetSize(size);
	tempCannyble->SetVelocity({ 0, 0 });

	return tempCannyble;
}

void CPracticeMode::HandleCollision()
{
	for (unsigned int index = 0; index < m_AllEnts.size(); index++)
	{
		if (m_pCurrPlayer->GetRect().IsIntersecting(m_AllEnts[index]->GetRect()) && m_pCurrPlayer != m_AllEnts[index])
		{
			SGD::Point tempPoint = m_pCurrPlayer->GetPosition();
			SGD::Rectangle rIntersect = m_AllEnts[index]->GetRect().ComputeIntersection(m_pCurrPlayer->GetRect());
			if (rIntersect.ComputeHeight() <= rIntersect.ComputeWidth())
			{
				if ((m_pCurrPlayer->GetRect().top == rIntersect.top))
					tempPoint.y = m_AllEnts[index]->GetPosition().y + m_AllEnts[index]->GetSize().height;
				else
					tempPoint.y = m_AllEnts[index]->GetPosition().y - m_pCurrPlayer->GetSize().height;
			}
			else if (rIntersect.ComputeHeight() >= rIntersect.ComputeWidth())
			{
				if ((m_pCurrPlayer->GetRect().left == rIntersect.left))
					tempPoint.x = m_AllEnts[index]->GetPosition().x + m_AllEnts[index]->GetSize().width;
				else
					tempPoint.x = m_AllEnts[index]->GetPosition().x - m_pCurrPlayer->GetSize().width;
			}

			m_pCurrPlayer->SetPosition(tempPoint);

			if (m_AllEnts[index]->GetType() == Entity::ENT_BALL)
			{
				m_bBalls = true;

				m_bHighWalls = false;
				m_bLowWalls = false;
				m_bRunner = false;
				m_bStriker = false;
				m_bBomber = false;
				m_bTank = false;
				m_bPowerups = false;
				m_bGorbi = false;
				m_bCannybles = false;
			}
			else if (m_AllEnts[index]->GetType() == Entity::ENT_WALL && dynamic_cast<CWall*>(m_AllEnts[index])->GetHeight() == true)
			{
				m_bHighWalls = true;

				m_bLowWalls = false;
				m_bBalls = false;
				m_bRunner = false;
				m_bStriker = false;
				m_bBomber = false;
				m_bTank = false;
				m_bPowerups = false;
				m_bGorbi = false;
				m_bCannybles = false;
			}
			else if (m_AllEnts[index]->GetType() == Entity::ENT_WALL && dynamic_cast<CWall*>(m_AllEnts[index])->GetHeight() == false)
			{
				m_bLowWalls = true;

				m_bHighWalls = false;
				m_bBalls = false;
				m_bRunner = false;
				m_bStriker = false;
				m_bBomber = false;
				m_bTank = false;
				m_bPowerups = false;
				m_bGorbi = false;
				m_bCannybles = false;
			}
			else if (m_AllEnts[index]->GetType() == Entity::ENT_CANNYBLE)
			{
				m_bCannybles = true;

				m_bHighWalls = false;
				m_bLowWalls = false;
				m_bBalls = false;
				m_bRunner = false;
				m_bStriker = false;
				m_bBomber = false;
				m_bTank = false;
				m_bPowerups = false;
				m_bGorbi = false;
			}
			else if (m_AllEnts[index]->GetType() == Entity::ENT_PUP)
			{
				m_bPowerups = true;

				m_bHighWalls = false;
				m_bLowWalls = false;
				m_bBalls = false;
				m_bRunner = false;
				m_bStriker = false;
				m_bBomber = false;
				m_bTank = false;;
				m_bGorbi = false;
				m_bCannybles = false;
			}
			else if (m_AllEnts[index]->GetType() == Entity::ENT_GORBI)
			{
				m_bGorbi = true;

				m_bHighWalls = false;
				m_bLowWalls = false;
				m_bBalls = false;
				m_bRunner = false;
				m_bStriker = false;
				m_bBomber = false;
				m_bTank = false;
				m_bPowerups = false;
				m_bCannybles = false;
			}
			else if (m_AllEnts[index] == m_pPlayer1 && m_pPlayer1->GetControllernumber() != 0)
			{
				m_bRunner = true;

				m_bHighWalls = false;
				m_bLowWalls = false;
				m_bBalls = false;
				m_bStriker = false;
				m_bBomber = false;
				m_bTank = false;
				m_bPowerups = false;
				m_bGorbi = false;
				m_bCannybles = false;
			}
			else if (m_AllEnts[index] == m_pPlayer2 && m_pPlayer2->GetControllernumber() != 0)
			{
				m_bStriker = true;

				m_bHighWalls = false;
				m_bLowWalls = false;
				m_bBalls = false;
				m_bRunner = false;
				m_bBomber = false;
				m_bTank = false;
				m_bPowerups = false;
				m_bGorbi = false;
				m_bCannybles = false;
			}
			else if (m_AllEnts[index] == m_pPlayer3 && m_pPlayer3->GetControllernumber() != 0)
			{
				m_bTank = true;

				m_bHighWalls = false;
				m_bLowWalls = false;
				m_bBalls = false;
				m_bRunner = false;
				m_bStriker = false;
				m_bBomber = false;
				m_bPowerups = false;
				m_bGorbi = false;
				m_bCannybles = false;
			}
			else if (m_AllEnts[index] == m_pPlayer4 && m_pPlayer4->GetControllernumber() != 0)
			{
				m_bBomber = true;

				m_bHighWalls = false;
				m_bLowWalls = false;
				m_bBalls = false;
				m_bRunner = false;
				m_bStriker = false;
				m_bTank = false;
				m_bPowerups = false;
				m_bGorbi = false;
				m_bCannybles = false;
			}
		}

		// Is the punch object colliding with a player who isn't it's owner
		if (m_AllEnts[index]->GetType() == Entity::ENT_PLAYER && m_pPunch != nullptr && m_AllEnts[index] != m_pPunch->GetOwner() && m_fPunchTimer > 0 && m_pPunch->GetRect().IsIntersecting(m_AllEnts[index]->GetRect()))
		{
			m_pCurrPlayer->SetControllernumber(1);
			m_pCurrPlayer = dynamic_cast<CPlayer*>(m_AllEnts[index]);
			m_pCurrPlayer->SetControllernumber(0);
		}
	}
}

Entity* CPracticeMode::CreatePunch(Entity* pOwner)
{
	m_pPunch = new CPunch;

	m_pPunch->SetOwner(pOwner);
	if (dynamic_cast<CPlayer*>(pOwner)->GetHeading())
	{
		m_pPunch->SetPosition(SGD::Point{ pOwner->GetPosition().x + pOwner->GetSize().width, pOwner->GetPosition().y + 30 });
	}
	else
		m_pPunch->SetPosition(SGD::Point{ pOwner->GetPosition().x - 40, pOwner->GetPosition().y + 30 });

	m_pPunch->SetHeading(dynamic_cast<CPlayer*>(pOwner)->GetHeading());
	m_pPunch->SetRotation(pOwner->GetRotation());
	m_pPunch->SetSize({ 30, 8 });

	m_pPunch->SetPunchTimer(0.1f);
	m_fPunchTimer = 0.1f;
	m_pEntities->AddEntity(m_pPunch, BUCKET_PUNCH);
	return m_pPunch;


}

void CPracticeMode::DeleteEntity(Entity* e)
{
	m_pEntities->RemoveEntity(e);
}